/*
 * 文件名： WcPayBankResBase.java
 * 
 * 工程名称: bis-web
 *
 * Gopay
 *
 * 创建日期： 2016年10月11日
 *
 * Copyright(C) 2016, by www.gopay.com.cn Inc.All rights reserved.
 *
 * 原始作者: 宣广海
 *
 */
package com.gopay.bis.web.controller.wcpay;

import java.util.Enumeration;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.gopay.remote.cashier.bis.CashierBgNotifyRemoteService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.gopay.bis.common.util.IpAddrUtil;
import com.gopay.bis.common.util.SendSmsUtils;
import com.gopay.bis.domain.order.OrderInfo;
import com.gopay.common.Result;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.domain.proccode.ProcCodeInfo;
import com.gopay.common.proccode.DicProcCodeService;
import com.gopay.common.util.HttpTransport;
import com.gopay.common.util.RSAEncoderUtil;
import com.gopay.remote.bank.WcPayInteractRemoteService;

/**
 * 公众号支付银行通知基类
 *
 * @author 宣广海
 *
 * @version
 *
 * @since 2016年10月11日
 */
public abstract class WcPayBankResBase {
	/**
	 * 定义日志对象
	 */
	private static Log logger = LogFactory.getLog(WcPayBankResBase.class);

	@Resource(name = "bisConfig")
	protected Map<String, String> bisConfig;

	@Resource(name = "wcPayInteractService")
	private WcPayInteractRemoteService wcPayInteractService;

	@Resource(name = "dicProcCodeService")
	private DicProcCodeService dicProcCodeService;

	@Resource(name = "notifyCashier")
	private HttpTransport notifyCashier;

	@Resource(name = "cashierBgNotifyRemoteService")
	private CashierBgNotifyRemoteService cashierBgNotifyRemoteService;

	@Resource(name = "smsConfig")
	private Map<String, String> smsConfig;

	/**
	 * 构建支付类对象
	 * 
	 * @param orderId
	 * @return
	 */
	protected abstract BaseMessage buildMessage(HttpServletRequest request);

	/**
	 * 构建返回收银台参数
	 * 
	 * @param request
	 * @return
	 */
	protected abstract OrderInfo buildOrderInfo(HttpServletRequest request, Result result);

	/**
	 * 验证返回参数
	 * 
	 * @param request
	 * @return
	 */
	protected abstract boolean checkParameters(HttpServletRequest request);

	/**
	 * 
	 * 功能描述：通知银行接口
	 *
	 * @param response
	 * @param orderInfo
	 * @return
	 * 
	 * @author 宣广海
	 *
	 * @since 2016年8月9日
	 *
	 * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
	 */
	protected abstract boolean notifyBank(HttpServletResponse response, OrderInfo orderInfo);

	/**
	 * 通知入口
	 * 
	 * @param request
	 * @param response
	 * @return
	 */
	protected void execute(HttpServletRequest request, HttpServletResponse response) {
		/**
		 * 打印请求参数
		 */
		this.displayRequestParameters(request, logger);
		/**
		 * 校验参数
		 */
		boolean isCheck = checkParameters(request);
		try {
			/**
			 * 校验参数通过
			 */
			if (isCheck) {
				OrderInfo orderInfo = null;
				/**
				 * 异步通知验签
				 */
				Result result = wcPayInteractService.verify(buildMessage(request));
				/**
				 * 构建发往收银台的参数
				 */
				orderInfo = buildOrderInfo(request, result);

				orderInfo.setSign(sign(orderInfo));// 前台通知cashier签名数据

				logger.error(orderInfo.getOrderId() + " Referer: " + request.getHeader("Referer") + " Ip: "
						+ IpAddrUtil.getRemoteRealIpAddr(request));

				if (result.isSuccess()) {
					if ((Boolean) result.getDefaultModel()) {

						Map<String, String> param = (Map<String, String>) result.getModel("isNotifyCashier");

						param.put("sign", signRes(param));// 后台通知cashier签名数据

						logger.error("notify cashier param:" + param);
						/**
						 * 通知cashier入账
						 */
						String isFront = param.get("isFront");
						if ("false".equals(isFront)) {
							/*notifyCashier.submit(param);*/ //生产优化10期 lx 2017-9-30 16:23:37
							cashierBgNotifyRemoteService.callBgNotify(param);
						}
						// 通知银行
						if (orderInfo.getIsNotify()) {
							notifyBank(response, orderInfo);
						}
					} else if (!(Boolean) result.getDefaultModel()) {
						/**
						 * 验签失败,不操作数据库也不通知cashier
						 */
						ProcCodeInfo procCodeInfo = dicProcCodeService
								.getProcCodeInfo(ProcCodeConstants.PROC_CODE_100E6040);
						orderInfo.setRetCode(ProcCodeConstants.PROC_CODE_100E6079);
						orderInfo.setRetMsg(procCodeInfo.getMessage());
						logger.error("平台订单[" + orderInfo.getOrderId() + "]验签失败!");
					}
					// TODO 执行不到下面流程
					else if (StringUtils.equals(ProcCodeConstants.PROC_CODE_100E6026, result.getResultCode())) {
						// 通知银行
						if (orderInfo.getIsNotify()) {
							notifyBank(response, orderInfo);
						}
					}
				} else {
					/**
					 * 验签异常,不操作数据库也不通知cashier
					 */
					ProcCodeInfo procCodeInfo = dicProcCodeService.getProcCodeInfo(result.getResultCode());
					orderInfo.setRetCode(result.getResultCode());
					orderInfo.setRetMsg(procCodeInfo.getMessage());
					if (StringUtils.equals(result.getResultCode(), ProcCodeConstants.PROC_CODE_100E5079)) {
						SendSmsUtils.sendSmsErr(smsConfig.get("switch"), smsConfig.get("mobile"),
								"注意!!!订单金额不一致,银行:" + orderInfo.getBankName() + "orderId:" + orderInfo.getOrderId());
					}
				}
			} else {
				logger.error("bank back notify parameters is null");
			}
		} catch (Exception e) {
			logger.error("BankResBase error：", e);
		}
	}

	/**
	 * 
	 * 功能描述：输出异步通知请求参数，威富通支付返回的request获取输入流，然后输出通知参数
	 *
	 * @param request
	 * @param logger
	 * 
	 * @author 宣广海
	 *
	 * @since 2016年8月9日
	 *
	 * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
	 */
	@SuppressWarnings("rawtypes")
	protected void displayRequestParameters(HttpServletRequest request, Log logger) {
		for (Enumeration enumeration = request.getParameterNames(); enumeration.hasMoreElements();) {
			String eleName = (String) enumeration.nextElement();
			String eleValue = request.getParameter(eleName);
			if (logger != null) {
				logger.error("map key: [" + eleName + "]，value: [" + eleValue + "]");
			}
		}
	}

	public String sign(OrderInfo orderInfo) {
		StringBuffer sign = new StringBuffer();
		String orderId = orderInfo.getOrderId();
		String amt = orderInfo.getAmt();
		String retCode = orderInfo.getRetCode();
		String retMsg = orderInfo.getRetMsg();
		String payStatus = orderInfo.getPayStatus();
		String notifyNum = orderInfo.getNotifyNum();
		String cardType = orderInfo.getCardType();
		sign.append(orderId).append("|");
		sign.append(amt).append("|");
		sign.append(retCode).append("|");
		sign.append(retMsg).append("|");
		sign.append(payStatus).append("|");
		sign.append(notifyNum).append("|");
		sign.append(cardType);
		try {
			return RSAEncoderUtil.sign(sign.toString());
		} catch (Exception e) {
			logger.error("bis通知cashier OrderInfo签名异常", e);
		}
		return "";
	}

	public String signRes(Map res) {
		StringBuffer sign = new StringBuffer();
		String orderId = (String) res.get("orderId");
		String amt = (String) res.get("amt");
		String retCode = (String) res.get("retCode");
		String retMsg = (String) res.get("retMsg");
		String payStatus = (String) res.get("payStatus");
		String notifyNum = (String) res.get("notifyNum");
		String cardType = (String) res.get("cardType");
		sign.append(orderId).append("|");
		sign.append(amt).append("|");
		sign.append(retCode).append("|");
		sign.append(retMsg).append("|");
		sign.append(payStatus).append("|");
		sign.append(notifyNum).append("|");
		sign.append(cardType);
		try {
			return RSAEncoderUtil.sign(sign.toString());
		} catch (Exception e) {
			logger.error("bis通知cashier Map签名异常", e);
		}
		return "";
	}
}
